#include <iostream>
#include <modbus.h>
#include <cstring>
#include <sstream>
#include <vector>

class ModbusHMI {
private:
    modbus_t *ctx;
    bool connected;

public:
    ModbusHMI() : ctx(nullptr), connected(false) {}

    ~ModbusHMI() {
        disconnect();
    }

    bool connect(const std::string& ip, int port) {
        // 创建 Modbus TCP 客户端
        ctx = modbus_new_tcp(ip.c_str(), port);
        if (!ctx) {
            std::cerr << "无法创建 Modbus 上下文\n";
            return false;
        }

        // 连接服务器
        if (modbus_connect(ctx) == -1) {
            std::cerr << "连接失败: " << modbus_strerror(errno) << "\n";
            modbus_free(ctx);
            ctx = nullptr;
            return false;
        }

        connected = true;
        std::cout << "成功连接到 Modbus 服务器 " << ip << ":" << port << "!\n";
        return true;
    }

    void disconnect() {
        if (ctx) {
            modbus_close(ctx);
            modbus_free(ctx);
            ctx = nullptr;
            connected = false;
        }
    }

    bool isConnected() const {
        return connected;
    }

    void showMenu() {
        std::cout << "\n========== Modbus HMI 模拟器 ==========\n";
        std::cout << "1. 读取保持寄存器\n";
        std::cout << "2. 写入单个保持寄存器\n";
        std::cout << "3. 写入多个保持寄存器\n";
        std::cout << "4. 读取线圈状态\n";
        std::cout << "5. 写入单个线圈\n";
        std::cout << "6. 显示连接状态\n";
        std::cout << "7. 断开连接\n";
        std::cout << "0. 退出程序\n";
        std::cout << "=====================================\n";
        std::cout << "请选择操作: ";
    }

    void readHoldingRegisters() {
        if (!connected) {
            std::cout << "错误: 未连接到服务器\n";
            return;
        }

        int addr, count;
        std::cout << "请输入起始地址: ";
        std::cin >> addr;
        std::cout << "请输入寄存器数量: ";
        std::cin >> count;

        if (count <= 0 || count > 125) {
            std::cout << "错误: 寄存器数量必须在 1-125 之间\n";
            return;
        }

        std::vector<uint16_t> reg_values(count);
        int rc = modbus_read_registers(ctx, addr, count, reg_values.data());
        if (rc == -1) {
            std::cerr << "读取失败: " << modbus_strerror(errno) << "\n";
        } else {
            std::cout << "读取成功:\n";
            for (int i = 0; i < rc; i++) {
                std::cout << "  地址 " << (addr + i) << ": " << reg_values[i] 
                         << " (0x" << std::hex << reg_values[i] << std::dec << ")\n";
            }
        }
    }

    void writeSingleRegister() {
        if (!connected) {
            std::cout << "错误: 未连接到服务器\n";
            return;
        }

        int addr, value;
        std::cout << "请输入寄存器地址: ";
        std::cin >> addr;
        std::cout << "请输入寄存器值: ";
        std::cin >> value;

        int rc = modbus_write_register(ctx, addr, value);
        if (rc == -1) {
            std::cerr << "写入失败: " << modbus_strerror(errno) << "\n";
        } else {
            std::cout << "写入成功! 地址 " << addr << " 已设置为 " << value << "\n";
        }
    }

    void writeMultipleRegisters() {
        if (!connected) {
            std::cout << "错误: 未连接到服务器\n";
            return;
        }

        int addr, count;
        std::cout << "请输入起始地址: ";
        std::cin >> addr;
        std::cout << "请输入寄存器数量: ";
        std::cin >> count;

        if (count <= 0 || count > 123) {
            std::cout << "错误: 寄存器数量必须在 1-123 之间\n";
            return;
        }

        std::vector<uint16_t> values(count);
        std::cout << "请输入 " << count << " 个寄存器值:\n";
        for (int i = 0; i < count; i++) {
            std::cout << "  地址 " << (addr + i) << " 的值: ";
            std::cin >> values[i];
        }

        int rc = modbus_write_registers(ctx, addr, count, values.data());
        if (rc == -1) {
            std::cerr << "写入失败: " << modbus_strerror(errno) << "\n";
        } else {
            std::cout << "成功写入 " << rc << " 个寄存器\n";
        }
    }

    void readCoils() {
        if (!connected) {
            std::cout << "错误: 未连接到服务器\n";
            return;
        }

        int addr, count;
        std::cout << "请输入起始地址: ";
        std::cin >> addr;
        std::cout << "请输入线圈数量: ";
        std::cin >> count;

        if (count <= 0 || count > 2000) {
            std::cout << "错误: 线圈数量必须在 1-2000 之间\n";
            return;
        }

        std::vector<uint8_t> coil_values(count);
        int rc = modbus_read_bits(ctx, addr, count, coil_values.data());
        if (rc == -1) {
            std::cerr << "读取失败: " << modbus_strerror(errno) << "\n";
        } else {
            std::cout << "读取成功:\n";
            for (int i = 0; i < rc; i++) {
                std::cout << "  线圈 " << (addr + i) << ": " 
                         << (coil_values[i] ? "ON" : "OFF") << "\n";
            }
        }
    }

    void writeSingleCoil() {
        if (!connected) {
            std::cout << "错误: 未连接到服务器\n";
            return;
        }

        int addr, value;
        std::cout << "请输入线圈地址: ";
        std::cin >> addr;
        std::cout << "请输入线圈值 (0=OFF, 1=ON): ";
        std::cin >> value;

        if (value != 0 && value != 1) {
            std::cout << "错误: 线圈值必须是 0 或 1\n";
            return;
        }

        int rc = modbus_write_bit(ctx, addr, value);
        if (rc == -1) {
            std::cerr << "写入失败: " << modbus_strerror(errno) << "\n";
        } else {
            std::cout << "写入成功! 线圈 " << addr << " 已设置为 " 
                     << (value ? "ON" : "OFF") << "\n";
        }
    }

    void showConnectionStatus() {
        if (connected) {
            std::cout << "当前状态: 已连接\n";
        } else {
            std::cout << "当前状态: 未连接\n";
        }
    }

    void run() {
        std::string ip;
        int port;

        std::cout << "欢迎使用 Modbus HMI 模拟器!\n";
        std::cout << "请输入 Modbus 服务器 IP 地址 (默认 127.0.0.1): ";
        std::getline(std::cin, ip);
        if (ip.empty()) ip = "127.0.0.1";

        std::cout << "请输入端口号 (默认 5020): ";
        std::string port_str;
        std::getline(std::cin, port_str);
        if (port_str.empty()) 
            port = 5020;
        else
            port = std::stoi(port_str);

        if (!connect(ip, port)) {
            std::cout << "连接失败，程序退出。\n";
            return;
        }

        int choice;
        while (true) {
            showMenu();
            std::cin >> choice;

            switch (choice) {
                case 1:
                    readHoldingRegisters();
                    break;
                case 2:
                    writeSingleRegister();
                    break;
                case 3:
                    writeMultipleRegisters();
                    break;
                case 4:
                    readCoils();
                    break;
                case 5:
                    writeSingleCoil();
                    break;
                case 6:
                    showConnectionStatus();
                    break;
                case 7:
                    disconnect();
                    std::cout << "已断开连接\n";
                    break;
                case 0:
                    std::cout << "感谢使用 Modbus HMI 模拟器!\n";
                    return;
                default:
                    std::cout << "无效选择，请重新输入\n";
                    break;
            }

            // 等待用户按键继续
            std::cout << "\n按回车键继续...";
            std::cin.ignore();
            std::cin.get();
        }
    }
};

int main() {
    ModbusHMI hmi;
    hmi.run();
    return 0;
}